import * as THREE from 'three';
import { useWindowSize } from '@vueuse/core';
import Stats from "three/examples/jsm/libs/stats.module";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
import { CSS2DRenderer, CSS2DObject } from 'three/examples/jsm/renderers/CSS2DRenderer';
import { CSS3DRenderer, CSS3DObject, CSS3DSprite } from 'three/examples/jsm/renderers/CSS3DRenderer';
// 使用BufferGeometryUtils合并几何体
import { mergeGeometries } from 'three/examples/jsm/utils/BufferGeometryUtils';
import img1 from '@/assets/img/brick_bump.jpg'
import img2 from '@/assets/img/brick_diffuse.jpg'
import img3 from '@/assets/img/brick_roughness.jpg'
import img4 from '@/assets/img/Carbon.png'
import img5 from '@/assets/img/roughness_map.jpg'
import img6 from '@/assets/img/Water_1_M_Normal.jpg'


export class threeTool {
  public scene: any
  public camera: any
  public renderer: any
  public controls: any
  public width: number
  public height: number
  public bgColor: any = 0xEEEEEE
  public canvasEl: any
  // 相机枚举类型
  public CameraType = {
    PERSPECTIVE: 0,
    ORTHOGRAPHIC: 1
  };
  public currentCamera = this.CameraType.PERSPECTIVE;
  public cameras: any;
  private animationFrameId: number | null = null;
  constructor() {
    const { width, height } = useWindowSize();
    this.width = width.value;
    this.height = height.value;
  }
  setCanvasMain(condition: { bgColor: THREE.ColorRepresentation, canvasEl: HTMLCanvasElement }) {
    this.bgColor = condition.bgColor;
    this.canvasEl = condition.canvasEl;
  }
  createCameras() {
    this.cameras = {
      [this.CameraType.PERSPECTIVE]: this.createPerspectiveCamera(),
      [this.CameraType.ORTHOGRAPHIC]: this.createOrthographicCamera()
    }
  }
  /**
   * 初始化3D场景
   * 创建场景、相机、渲染器、控制器以及基本几何体
   */
  initScene() {
    if (!this.canvasEl) {
      throw new Error('Canvas element not set');
    }
    // 1. 创建场景
    this.scene = new THREE.Scene();  // 创建一个新的Three.js场景对象
    this.scene.background = new THREE.Color(this.bgColor);  // 设置场景的背景颜色为实例变量color指定的颜色

    // 2. 创建相机
    // 确保相机已创建
    if (!this.cameras) {
      this.createCameras();
    }

    // 4. 初始化渲染器
    this.renderer = new THREE.WebGLRenderer({
      canvas: this.canvasEl,
      antialias: true, // 开启抗锯齿
      alpha: true,     // 允许透明背景
      powerPreference: "high-performance", // 高性能模式
      precision: 'mediump'  // 使用中等精度
    });
    // 设置像素比和尺寸
    this.renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
    this.renderer.setSize(this.width, this.height);
    this.renderer.shadowMap.enabled = true;// 开启阴影
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap; // 柔和阴影

    // 5. 创建控制器 - 使用当前激活的相机
    const activeCamera = this.cameras[this.currentCamera];
    this.controls = new OrbitControls(activeCamera, this.renderer.domElement);
    this.controls.enableDamping = true; // 启用阻尼（惯性移动效果）
    this.controls.dampingFactor = 0.05; // 阻尼系数
    this.controls.screenSpacePanning = false; // 启用屏幕空间平移
    this.controls.minDistance = 1; // 设置相机最小距离
    this.controls.maxDistance = 20; // 设置相机最大距离
    this.controls.maxPolarAngle = Math.PI / 2; // 设置相机最大极角（上下旋转角度）
    this.controls.autoRotate = false;    // 自动旋转
    this.controls.autoRotateSpeed = 1.0;
    // 限制垂直旋转角度
    // this.controls.minPolarAngle = Math.PI / 6; // 30度
    // this.controls.maxPolarAngle = Math.PI / 2; // 90度

    // 禁用平移
    this.controls.enablePan = false;

    // 添加坐标轴辅助器
    //红色代表 X 轴. 绿色代表 Y 轴. 蓝色代表 Z 轴.
    const axesHelper = new THREE.AxesHelper(5)
    // this.scene.add(axesHelper)
    //创建网格型地面
    const grid = new THREE.GridHelper(100, 100, 0x888888, 0x444444);
    // this.scene.add(grid);
  }
  creatGroup() {
    if (!this.scene) {
      throw new Error('Scene not initialized');
    }
    //创建一个模型组
    const group = new THREE.Group();
    this.scene.add(group);

    // 车身
    const badyGeo = new THREE.BoxGeometry(2, 0.5, 1);
    const badyMat = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
    const badyMesh = new THREE.Mesh(badyGeo, badyMat);
    group.add(badyMesh);

    // 轮胎
    const wheelGeo = new THREE.CylinderGeometry(0.2, 0.2, 0.5, 32);
    const wheelMat = new THREE.MeshBasicMaterial({ color: 0x000000 });
    const wheelMesh1 = new THREE.Mesh(wheelGeo, wheelMat);
    wheelMesh1.position.set(-0.8, -0.25, 0.5);
    wheelMesh1.rotation.z = Math.PI / 2; // 修正轮胎方向
    group.add(wheelMesh1);

    const wheelMesh2 = new THREE.Mesh(wheelGeo, wheelMat);
    wheelMesh2.position.set(-0.8, -0.25, -0.5);
    wheelMesh2.rotation.z = Math.PI / 2; // 修正轮胎方向
    group.add(wheelMesh2);

    const wheelMesh3 = new THREE.Mesh(wheelGeo, wheelMat);
    wheelMesh3.position.set(0.8, -0.25, 0.5);
    wheelMesh3.rotation.z = Math.PI / 2; // 修正轮胎方向
    group.add(wheelMesh3);

    const wheelMesh4 = new THREE.Mesh(wheelGeo, wheelMat);
    wheelMesh4.position.set(0.8, -0.25, -0.5);
    wheelMesh4.rotation.z = Math.PI / 2; // 修正轮胎方向
    group.add(wheelMesh4);

    // 移动整个汽车组
    group.position.x = -2;

    // 灯光
    const light = new THREE.PointLight(0xffffff, 1, 100);
    light.position.set(0, 0, 5);
    this.scene.add(light);

    // 环境光
    const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
    this.scene.add(ambientLight);
  }

  // 主渲染循环
  animateFun() {
    if (!this.scene || !this.renderer || !this.controls || !this.cameras) {
      throw new Error('Scene not properly initialized');
    }

    this.animationFrameId = requestAnimationFrame(this.animateFun.bind(this));

    // 获取当前激活的相机
    const activeCamera = this.cameras[this.currentCamera];
    this.controls.update(); // 必须每帧更新控制器

    this.renderer.render(this.scene, activeCamera);
  }

  /**
   * 创建一个透视相机
   * @returns {THREE.PerspectiveCamera} 返回一个配置好的透视相机对象
   */
  createPerspectiveCamera(): THREE.PerspectiveCamera {
    // 创建一个透视相机，参数分别为：视野角度(FOV)、宽高比、近裁剪面、远裁剪面
    const camera = new THREE.PerspectiveCamera(75, this.width / this.height, 0.1, 1000);
    // 设置相机的位置，x=0, y=2, z=5
    camera.position.set(0, 3, 8);
    camera.lookAt(0, 0, 0);
    camera.far = 1000;  // 减小远平面距离
    camera.near = 0.1;  // 增大近平面距离
    // 返回配置好的相机对象
    return camera;
  }
  /**
   * 创建一个正交投影相机
   * @returns {THREE.OrthographicCamera} 返回创建的正交投影相机对象
   */
  createOrthographicCamera(): THREE.OrthographicCamera {
    // 计算相机的宽高比，基于场景的宽度和高度
    const aspect = this.width / this.height;
    // 调整正交相机的参数以匹配透视相机的视口
    const frustumSize = 5;
    // 创建正交投影相机，参数分别为左右、上下、近远平面
    const camera = new THREE.OrthographicCamera(frustumSize * aspect / -2,
      frustumSize * aspect / 2,
      frustumSize / 2,
      frustumSize / -2, 0.1, 100);
    // 设置相机位置
    camera.position.set(0, 2, 5);
    // 让相机看向原点
    camera.lookAt(0, 0, 0);
    // 返回创建的相机对象
    return camera;
  }
  toggleCamera(switchcurr: ((arg0: number) => void) | undefined) {
    if (!this.controls || !this.cameras || !this.scene) {
      throw new Error('Controls, cameras or scene not initialized');
    }


    this.currentCamera = this.currentCamera === this.CameraType.PERSPECTIVE
      ? this.CameraType.ORTHOGRAPHIC
      : this.CameraType.PERSPECTIVE;

    // 更新控制器绑定的相机
    this.controls.object = this.cameras[this.currentCamera];
    this.controls.update();
    if (switchcurr) {
      switchcurr(this.currentCamera)
    }
  }

  watchUpdate(width: number, height: number) {
    if (!this.cameras || !this.renderer) {
      throw new Error('Cameras or renderer not initialized');
    }

    const aspect = width / height;

    if (this.currentCamera === this.CameraType.PERSPECTIVE) {
      // 更新透视相机
      const perspectiveCamera = this.cameras[this.CameraType.PERSPECTIVE] as THREE.PerspectiveCamera;
      perspectiveCamera.aspect = aspect;
      perspectiveCamera.updateProjectionMatrix();
    }
    if (this.currentCamera === this.CameraType.ORTHOGRAPHIC) {
      // 更新正交相机
      const orthographicCamera = this.cameras[this.CameraType.ORTHOGRAPHIC] as THREE.OrthographicCamera;
      const frustumSize = 5;
      orthographicCamera.left = -frustumSize * aspect / 2;
      orthographicCamera.right = frustumSize * aspect / 2;
      orthographicCamera.updateProjectionMatrix();
    }

    this.renderer.setSize(width, height);
  }
  stopAnimation() {
    if (this.animationFrameId !== null) {
      cancelAnimationFrame(this.animationFrameId);
      this.animationFrameId = null;
    }
  }
  dispose() {
    // 先停止动画
    this.stopAnimation();
    // 释放GPU内存
    this.scene.traverse((obj: { isMesh: any; geometry: { dispose: () => void; }; material: { dispose: () => void; }; }) => {
      if (obj instanceof THREE.Mesh) {
        obj.geometry.dispose();
        if (Array.isArray(obj.material)) {
          obj.material.forEach(material => material.dispose());
        } else {
          obj.material.dispose();
        }
      }
    });
    this.controls.dispose();
    if (this.renderer) {
      this.renderer.dispose();
      this.renderer.forceContextLoss();
    }
    // 清空引用
    this.scene = null;
    this.camera = null;
    this.renderer = null;
    this.controls = null;
    this.cameras = {};
  }
}
export class GeometryClass extends threeTool {
  private cubeAnimationFrameId: number | null = null;
  private cube: any
  public wireframe: boolean;
  constructor(scene: THREE.Scene,wireframe: boolean) {
    super()
    this.scene = scene;
    this.wireframe = wireframe
  }
  /**
  * 创建立方体的方法
  * 该方法用于在场景中创建一个线框模式的绿色立方体
  * @param box 立方体的参数
  * @returns {THREE.Mesh} 返回创建的立方体对象
  * @width — X 轴上面的宽度，默认值为 1。
  * @height — Y 轴上面的高度，默认值为 1。
  * @depth — Z 轴上面的深度，默认值为 1。
  * @widthSegments — （可选）宽度的分段数，默认值是 1。
  * @heightSegments — （可选）高度的分段数，默认值是 1。
  * @depthSegments — （可选）深度的分段数，默认值是 1
  */
  createBox(box: { width: number | undefined; height: number | undefined; depth: number | undefined; widthSegments?: number | undefined; heightSegments?: number | undefined; depthSegments?: number | undefined; }): THREE.Mesh {
    // 3. 创建立方体
    const geometry = new THREE.BoxGeometry(box.width, box.height, box.depth, box.widthSegments, box.heightSegments, box.depthSegments); // 创建一个2x2x2大小的立方体几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0x00ff00, // 设置材质颜色为绿色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const boxGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(boxGeo); // 将创建的立方体网格添加到场景中
    return boxGeo
  }
  /**
   * @param sphere 球体的参数
   * @returns {THREE.Mesh} 返回创建的球体对象
   * @radius 半径
   * @widthSegments — 水平分段数（沿着经线分段），最小值为3，默认值为32。
   * @heightSegments — 垂直分段数（沿着纬线分段），最小值为2，默认值为16。
   * @phiStart — 指定水平（经线）起始角度，默认值为0。。
   * @phiLength — 指定水平（经线）扫描角度的大小，默认值为 Math.PI * 2。
   * @thetaStart — 指定垂直（纬线）起始角度，默认值为0。
   * @thetaLength — 指定垂直（纬线）扫描角度大小，默认值为 Math.PI。
   */
  createSphere(sphere: { radius: number | undefined; widthSegments: number | undefined; heightSegments: number | undefined; phiStart?: number | undefined; phiLength?: number | undefined; thetaStart?: number | undefined; thetaLength?: number | undefined; }): THREE.Mesh {

    const geometry = new THREE.SphereGeometry(sphere.radius, sphere.widthSegments, sphere.heightSegments, sphere.phiStart, sphere.phiLength, sphere.thetaStart, sphere.thetaLength); // 创建一个球体几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0xff0000, // 设置材质颜色为红色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const sphereGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(sphereGeo); // 将创建的球体网格添加到场景中
    return sphereGeo
  }
  /**
   * @param cylinder 圆柱体的参数
   * @returns {THREE.Mesh} 返回创建的圆柱体对象
   * @radiusTop — 圆柱的顶部半径，默认值为1。
   * @radiusBottom — 圆柱的底部半径，默认值为1。
   * @height — 圆柱的高度，默认值为2。
   * @radialSegments — 圆柱的径向分段数，默认值为8。
   * @heightSegments — 圆柱的逐高度方向分段数，默认值为1。
   * @openEnded — 一个Boolean值，表示是否没有顶面和底面。默认值为false有顶面和底面。
   * @thetaStart — 圆柱的起始角度，默认值为0。
   * @thetaLength — 圆柱的扫描角度大小，默认值为 Math.PI * 2。
   *
   */
  createCylinder(cylinder: { radiusTop: number | undefined; radiusBottom: number | undefined; height: number | undefined; radialSegments?: number | undefined; heightSegments?: number | undefined; openEnded?: boolean | undefined; thetaStart?: number | undefined; thetaLength?: number | undefined; }): THREE.Mesh {
    const geometry = new THREE.CylinderGeometry(cylinder.radiusTop, cylinder.radiusBottom, cylinder.height, cylinder.radialSegments, cylinder.heightSegments, cylinder.openEnded, cylinder.thetaStart, cylinder.thetaLength); // 创建一个圆柱几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0x0000ff, // 设置材质颜色为蓝色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const cylinderGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(cylinderGeo); // 将创建的圆柱网格添加到场景中
    return cylinderGeo
  }
  /**
   *
   * @returns {THREE.Mesh} 返回创建的圆环对象
   * @radius — 圆环的半径，默认值为1。
   * @tube — 管道的半径，默认值为0.4。
   * @radialSegments — 圆环的分段数，默认值为8。
   * @tubularSegments — 管道的分段数，默认值为6。
   * @arc — 圆环的圆心角，默认值为Math.PI * 2。
   *
   */
  createTorus(torus: { radius: number | undefined; tube: number | undefined; radialSegments?: number | undefined; tubularSegments?: number | undefined; arc?: number | undefined;}): THREE.Mesh {
    const geometry = new THREE.TorusGeometry(torus.radius, torus.tube, torus.radialSegments, torus.tubularSegments, torus.arc); // 创建一个圆环几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0xff00ff, // 设置材质颜色为紫色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const torusGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(torusGeo); // 将创建的圆环网格添加到场景中
    return torusGeo
  }
  /**
   *
   * @returns {THREE.Mesh} 返回创建的平面对象
   * @width — 平面对象的宽度，默认值为1。
   * @height — 平面对象的高度，默认值为1。
   * @widthSegments — 平面对象的宽度分段数，默认值为1。
   * @heightSegments — 平面对象的高度分段数，默认值为1。
   *
   */
  createPlane(plane: { width: number | undefined; height: number | undefined; widthSegments?: number | undefined; heightSegments?: number | undefined; }): THREE.Mesh {
    const geometry = new THREE.PlaneGeometry(plane.width, plane.height, plane.widthSegments, plane.heightSegments); // 创建一个平面几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0xffff00, // 设置材质颜色为黄色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const planeGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(planeGeo); // 将创建的平面网格添加到场景中
    return planeGeo
  }
  /**
   *
   * @returns {THREE.Mesh} 返回创建的圆环缓冲对象
   * @radius — 圆环的半径，默认值为1。
   * @tube — 管道的半径，默认值为0.4。
   * @tubularSegments  — 圆环的分段数，默认值为8。
   * @radialSegments  — 管道的分段数，默认值为6。
   * @p — 这个值决定了几何体将绕着其旋转对称轴旋转多少次，默认值是2。
   * @q — 这个值决定了几何体将绕着其内部圆环旋转多少次，默认值是3。
   */
  createTorusKnot(torusKnot: { radius: number | undefined; tube: number | undefined; tubularSegments?: number | undefined; radialSegments?: number | undefined; p?: number | undefined; q?: number | undefined; }): THREE.Mesh {
    const geometry = new THREE.TorusKnotGeometry(torusKnot.radius, torusKnot.tube, torusKnot.tubularSegments, torusKnot.radialSegments, torusKnot.p, torusKnot.q); // 创建一个圆环几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0x00ffff, // 设置材质颜色为青色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const torusKnotGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(torusKnotGeo); // 将创建的圆环网格添加到场景中
    return torusKnotGeo
  }
  /**
   *
   * @returns {THREE.Mesh} 返回创建的二十面体对象
   * @radius — 二十面体的半径，默认值为1。
   * @detail — 二十面体的细节级别，默认值为0。
   */
  createIcosahedron(icosahedron: { radius: number | undefined; detail?: number | undefined; }): THREE.Mesh {
    const geometry = new THREE.IcosahedronGeometry(icosahedron.radius, icosahedron.detail); // 创建一个二十面体几何体
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0xff0000, // 设置材质颜色为红色（十六进制表示）
      wireframe: this.wireframe // 设置为线框模式，仅显示网格结构
    });
    const icosahedronGeo = new THREE.Mesh(geometry, material); // 创建网格对象，将几何体和材质组合
    this.scene.add(icosahedronGeo); // 将创建的二十面体网格添加到场景中
    return icosahedronGeo
  }
  animateCube() {
    if (!this.cube) return;

    this.cube.rotation.x += 0.01;
    this.cube.rotation.y += 0.01;

    this.cubeAnimationFrameId = requestAnimationFrame(this.animateCube.bind(this));
  }
  stopCubeAnimation() {
    if (this.cubeAnimationFrameId !== null) {
      cancelAnimationFrame(this.cubeAnimationFrameId);
      this.cubeAnimationFrameId = null;
    }
  }
  dispose(): void {
    super.dispose();
    this.stopCubeAnimation();
    this.cube = null;
  }
}

export class MaterialClass {
  createNormalMaterial(){
    const material = new THREE.MeshNormalMaterial(); // 创建一个法线材质对象
    return material
  }
  /**
   * @name 创建基础材质
   * @returns {THREE.MeshBasicMaterial} 返回创建的基础材质对象
   * @description 适用场景：调试几何体、HUD元素、X射线效果
   */
  createBasicMaterial(): THREE.MeshBasicMaterial {
    const material = new THREE.MeshBasicMaterial({ // 创建基础材质对象
      color: 0xff0000, // 设置材质颜色为红色（十六进制表示）
      wireframe: false, // 设置为线框模式，仅显示网格结构
      transparent: true, // 开启透明度
      opacity: 0.7,             // 透明度值
      side: THREE.DoubleSide    // 双面渲染
    });
    return material
  }
  /**
   * @name 标准材质(MeshStandardMaterial)
   */
  createStandardMaterial(): THREE.MeshStandardMaterial {
    const material = new THREE.MeshStandardMaterial({ // 创建标准材质对象
      color: 0xff0000, // 设置材质颜色为红色（十六进制表示）
      roughness: 0.5,           // 粗糙度 (0:镜面, 1:磨砂)
      metalness: 0.8,           // 金属度 (0:非金属, 1:金属)
      //envMap: cubeTexture,      // 环境贴图
      //normalMap: normalTexture, // 法线贴图
      //aoMap: aoTexture,         // 环境光遮蔽贴图
      aoMapIntensity: 1.0       // AO强度
    });
    return material
  }
  /**
   * @name 物理材质(MeshPhysicalMaterial)
   */
  createPhysicalMaterial(): THREE.MeshPhysicalMaterial {
    const material = new THREE.MeshPhysicalMaterial({
      color: 0xff0000,           // 颜色
      clearcoat: 1.0,           // 清漆层强度
      clearcoatRoughness: 0.1,  // 清漆粗糙度
      sheen: 0.5,               // 织物绒感
      transmission: 0.9,        // 透光率（玻璃效果）
      ior: 1.5,                 // 折射率（钻石：2.4，水：1.33）
    });
    return material
  }
}
/**
 * @name 渲染方式
 * @description
 * 1. 几何体复用：相同物体共享几何体
 * const boxGeometry = new THREE.BoxGeometry();
 * const material = new THREE.MeshBasicMaterial({ color: 0xff0000 });
 * const mesh1 = new THREE.Mesh(boxGeometry, material);
 * const mesh2 = new THREE.Mesh(boxGeometry, material.clone());
 * 2.及时释放内存：使用完几何体后，及时释放内存
 *
 * 3.避免每帧创建：在动画循环外创建几何体
 */
export class RenderClass {
  private loader: THREE.TextureLoader = new THREE.TextureLoader();
  /**
   * @name 实例化渲染
   * @description 1000个立方体，Draw Call从1000次降为1次
   */
  InstantiateRender() {
    const geometry = new THREE.BoxGeometry(1, 1, 1);
    const material = new THREE.MeshBasicMaterial();
    const instances = new THREE.InstancedMesh(geometry, material, 1000);

    // 设置每个实例的位置和旋转
    const matrix = new THREE.Matrix4();
    for (let i = 0; i < 1000; i++) {
      matrix.setPosition(
        Math.random() * 100 - 50,
        Math.random() * 100 - 50,
        Math.random() * 100 - 50
      );
      instances.setMatrixAt(i, matrix);
    }
    return instances
  }
  /**
   * @name 合并多个几何体
   * @type mergeBufferGeometries === mergeGeometries
   */
  mergeGeometry() {
    const geometries = [];
    for (let i = 0; i < 100; i++) {
      const box = new THREE.BoxGeometry(0.2, 0.2, 0.2);
      box.translate(Math.random()*10-5, Math.random()*10-5, Math.random()*10-5);
      geometries.push(box);
    }

    // 合并为单个几何体（减少Draw Call）
    const mergedGeometry = mergeGeometries(geometries);
    const material = new THREE.MeshNormalMaterial();
    const mesh = new THREE.Mesh(mergedGeometry, material);
    return mesh
  }
  /**
   * @name 几何体操作进阶技巧
   *  顶点修改：创建波浪平面
   */
  geometryOperation() {
    const plane = new THREE.PlaneGeometry(10, 10, 50, 50);
    const positions = plane.attributes.position.array;

    // 遍历顶点添加波浪效果
    for (let i = 0; i < positions.length; i += 3) {
      const x = positions[i];
      const z = positions[i+2];

      // 使用正弦函数生成高度
      positions[i+1] = Math.sin(x * 0.5) * Math.cos(z * 0.5) * 1.5;
    }

    // 通知Three.js更新
    plane.attributes.position.needsUpdate = true;
    const material = new THREE.MeshBasicMaterial({ color: 0x00ff00, wireframe: true });
    const mesh = new THREE.Mesh(plane, material);
    return mesh
  }
  /**
   * @name 技巧进阶：UV坐标操作 && 法线重计算
   * @description UV坐标操作：纹理映射 && 法线重计算
   */
  uvAndNormal() {
    const geometry = new THREE.BoxGeometry(2, 2, 2);
    const uvs = geometry.attributes.uv.array;

    // 修改UV坐标实现特殊纹理映射
    for (let i = 0; i < uvs.length; i += 2) {
      uvs[i] *= 2;   // U坐标拉伸
      uvs[i+1] *= 2; // V坐标拉伸
    }

    geometry.computeVertexNormals(); // 自动计算法线

    // 手动修改法线
    const normals = geometry.attributes.normal.array;
    for (let i = 0; i < normals.length; i += 3) {
      normals[i] = 0;   // X分量
      normals[i+1] = 1; // Y分量（指向正上方）
      normals[i+2] = 0; // Z分量
    }
    geometry.attributes.normal.needsUpdate = true;

    // 应用纹理
    const texture = this.loader.load(img1);
    const material2 = new THREE.MeshBasicMaterial({ map: texture });
    texture.colorSpace = THREE.SRGBColorSpace;
    const materials = [
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img1)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img2)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img3)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img4)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img5)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img6)}),
    ];
    const cube = new THREE.Mesh(geometry, materials);
    return cube
  }
  loadColorTexture( path: string ) {
    const texture = this.loader.load( path );
    texture.colorSpace = THREE.SRGBColorSpace;
    return texture;
  }

  uvAndNormal2() {
    const geometry = new THREE.BoxGeometry(2, 2, 2);

    const materials = [
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img1)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img2)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img3)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img4)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img5)}),
      new THREE.MeshBasicMaterial({map: this.loadColorTexture(img6)}),
    ];
    const cube = new THREE.Mesh(geometry, materials);
    return cube
  }
  uvAndNormal3() {
    const geometry = new THREE.BoxGeometry(2, 2, 2);

    // 六个面的文字
    const faceTexts = [
        "+X 右面",
        "-X 左面",
        "+Y 上面",
        "-Y 下面",
        "+Z 前面",
        "-Z 后面"
    ];
    const colors = [
        "#ff6b6b", // 红色 - 右面
        "#4ecdc4", // 青色 - 左面
        "#45b7d1", // 蓝色 - 上面
        "#ffaa1d", // 橙色 - 下面
        "#96ceb4", // 绿色 - 前面
        "#ff8c94"  // 粉色 - 后面
    ];

    // 为每个面创建材质
    const materials = faceTexts.map((text,index) => {
        const texture = this.createTextTexture(text,colors[index]);
        texture.colorSpace = THREE.SRGBColorSpace;
        return new THREE.MeshBasicMaterial({
            map: texture,
            side: THREE.FrontSide
        });
    })
    const cube = new THREE.Mesh(geometry, materials);
    return cube
  }

  // 用于在每个面上绘制文字的函数
  createTextTexture(text:string,color:string, width = 256, height = 256) {
      // 创建Canvas元素
      const canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;

      // 获取2D上下文
      const context = canvas.getContext('2d') as CanvasRenderingContext2D;

      // 设置背景
      context.fillStyle = color;
      context.fillRect(0, 0, width, height);

      // 设置文字样式
      context.font = 'bold 40px Arial';
      context.fillStyle = '#ffffff';
      context.textAlign = 'center';
      context.textBaseline = 'middle';

      // 绘制文字
      context.fillText(text, width / 2, height / 2);

      // 创建纹理
      const texture = new THREE.CanvasTexture(canvas);
      return texture;
  }

}

export class LightClass {
  /**
   * @name 创建环境光（均匀照亮所有表面）
   * @description
   * 特性：
   *  1.无方向性
   *  2.不产生阴影
   *  3.用于模拟间接光照
   */
  createAmbientLight() {
    const ambientLight = new THREE.AmbientLight(
      0x404040, // 光线颜色
      1.0       // 光照强度
    );
    return ambientLight
  }
  /**
   * @name 平行光(DirectionalLight)
   * @description 太阳光、室外场景全局光照
   */
  createDirectionalLight() {
    const directionalLight = new THREE.DirectionalLight(
      0xffffff, // 颜色
      0.8       // 强度
    );

    // 设置光源位置（位置决定方向）
    directionalLight.position.set(5, 10, 7.5);

    // 启用阴影
    directionalLight.castShadow = true;

    // 阴影质量配置
    directionalLight.shadow.mapSize.width = 2048;
    directionalLight.shadow.mapSize.height = 2048;
    directionalLight.shadow.camera.near = 0.5;
    directionalLight.shadow.camera.far = 50;
    return directionalLight
  }
  /**
   * @name 点光源(PointLight)
   * 衰减公式：$ intensity / (distance^2) $
   */
  createPointLight() {
    const pointLight = new THREE.PointLight(
      0xff0000, // 红色光源
      1.0,      // 强度
      10,       // 照射距离
      0.5       // 衰减系数
    );

    pointLight.position.set(0, 3, 0);
    pointLight.castShadow = true;

    // 添加光源辅助器
    const helper = new THREE.PointLightHelper(pointLight);
  }
  /**
   * @name 聚光灯(SpotLight)
   */
  createSpotLight() {
    const spotLight = new THREE.SpotLight(
      0x00ff00, // 颜色
      1.0,      // 强度
      20,       // 距离
      Math.PI/4, // 照射角度（弧度）
      0.25,     // 边缘模糊度
      0.5       // 衰减系数
    );

    spotLight.position.set(0, 10, 0);
    spotLight.target.position.set(0, 0, 0); // 照射目标
    // scene.add(spotLight.target);

    // 聚光灯光锥可视化
    const spotHelper = new THREE.SpotLightHelper(spotLight);
    // scene.add(spotHelper);
  }
}
